//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_testcase_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_entry_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/testcase_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/user_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/watch_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/notices/notices_testcase"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_entry_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_testcase_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_watch_api"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectTestCaseApiImpl) LinkSprit(ctx context.Context, req *project_testcase_api.LinkSpritRequest) (*project_testcase_api.LinkSpritResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.LinkSpritResponse{
			Code:   project_testcase_api.LinkSpritResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.LinkSpritResponse{
			Code:   project_testcase_api.LinkSpritResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.LinkSpritResponse{
			Code:   project_testcase_api.LinkSpritResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_testcase_api.LinkSpritResponse{
			Code:   project_testcase_api.LinkSpritResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查关联是否已经存在
	exist, err := testcase_dao.LinkSpritDao.Exist(ctx, req.CaseId, req.SpritId)
	if err != nil {
		return nil, err
	}
	if exist {
		return &project_testcase_api.LinkSpritResponse{
			Code: project_testcase_api.LinkSpritResponse_CODE_OK,
		}, nil
	}

	//检查测试用例是否存在
	caseItem, err := testcase_dao.CaseInfoDao.Get(ctx, req.CaseId, req.ProjectId)
	if err != nil {
		return &project_testcase_api.LinkSpritResponse{
			Code:   project_testcase_api.LinkSpritResponse_CODE_NO_CASE,
			ErrMsg: "测试用例不存在",
		}, nil
	}
	//检查工作计划是否存在
	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.SpritId, req.ProjectId)
	if err != nil {
		return &project_testcase_api.LinkSpritResponse{
			Code:   project_testcase_api.LinkSpritResponse_CODE_NO_SPRIT,
			ErrMsg: "工作计划不存在",
		}, nil
	}
	if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_SPRIT) {
		return &project_testcase_api.LinkSpritResponse{
			Code:   project_testcase_api.LinkSpritResponse_CODE_NO_SPRIT,
			ErrMsg: "工作计划不存在",
		}, nil
	}
	//检查权限
	canUpdate := false
	if projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin || entryItem.EntryPerm.UpdateForAll {
		canUpdate = true
	} else {
		for _, userId := range entryItem.EntryPerm.ExtraUpdateUserIdList {
			if userId == sessionItem.UserId {
				canUpdate = true
			}
		}
	}
	if !canUpdate {
		return &project_testcase_api.LinkSpritResponse{
			Code:   project_testcase_api.LinkSpritResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = testcase_dao.LinkSpritDao.Insert(sessCtx, &testcase_dao.LinkSpritDbItem{
			CaseId:  req.CaseId,
			SpritId: req.SpritId,
		})
		if err != nil {
			return nil, err
		}
		return &project_testcase_api.LinkSpritResponse{
			Code: project_testcase_api.LinkSpritResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addLinkSpritEvent(sessionItem, projectItem, caseItem, entryItem, time.Now().UnixNano()/1e6)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_testcase.LinkSpritNotice{
		ProjectId: req.ProjectId,
		CaseId:    req.CaseId,
		SpritId:   req.SpritId,
	})
	return ret.(*project_testcase_api.LinkSpritResponse), nil
}

func (apiImpl *ProjectTestCaseApiImpl) UnlinkSprit(ctx context.Context, req *project_testcase_api.UnlinkSpritRequest) (*project_testcase_api.UnlinkSpritResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.UnlinkSpritResponse{
			Code:   project_testcase_api.UnlinkSpritResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.UnlinkSpritResponse{
			Code:   project_testcase_api.UnlinkSpritResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.UnlinkSpritResponse{
			Code:   project_testcase_api.UnlinkSpritResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_testcase_api.UnlinkSpritResponse{
			Code:   project_testcase_api.UnlinkSpritResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查关联是否已经存在
	exist, err := testcase_dao.LinkSpritDao.Exist(ctx, req.CaseId, req.SpritId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_testcase_api.UnlinkSpritResponse{
			Code: project_testcase_api.UnlinkSpritResponse_CODE_OK,
		}, nil
	}

	//检查测试用例是否存在
	caseItem, err := testcase_dao.CaseInfoDao.Get(ctx, req.CaseId, req.ProjectId)
	if err != nil {
		return &project_testcase_api.UnlinkSpritResponse{
			Code:   project_testcase_api.UnlinkSpritResponse_CODE_NO_CASE,
			ErrMsg: "测试用例不存在",
		}, nil
	}

	//检查工作计划是否存在
	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.SpritId, req.ProjectId)
	if err != nil {
		return &project_testcase_api.UnlinkSpritResponse{
			Code:   project_testcase_api.UnlinkSpritResponse_CODE_NO_SPRIT,
			ErrMsg: "工作计划不存在",
		}, nil
	}
	if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_SPRIT) {
		return &project_testcase_api.UnlinkSpritResponse{
			Code:   project_testcase_api.UnlinkSpritResponse_CODE_NO_SPRIT,
			ErrMsg: "工作计划不存在",
		}, nil
	}
	//检查权限
	canUpdate := false
	if projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin || entryItem.EntryPerm.UpdateForAll {
		canUpdate = true
	} else {
		for _, userId := range entryItem.EntryPerm.ExtraUpdateUserIdList {
			if userId == sessionItem.UserId {
				canUpdate = true
			}
		}
	}
	if !canUpdate {
		return &project_testcase_api.UnlinkSpritResponse{
			Code:   project_testcase_api.UnlinkSpritResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = testcase_dao.LinkSpritDao.Remove(sessCtx, req.CaseId, req.SpritId)
		if err != nil {
			return nil, err
		}
		return &project_testcase_api.UnlinkSpritResponse{
			Code: project_testcase_api.UnlinkSpritResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addUnlinkSpritEvent(sessionItem, projectItem, caseItem, entryItem, time.Now().UnixNano()/1e6)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_testcase.UnlinkSpritNotice{
		ProjectId: req.ProjectId,
		CaseId:    req.CaseId,
		SpritId:   req.SpritId,
	})
	return ret.(*project_testcase_api.UnlinkSpritResponse), nil
}

func (apiImpl *ProjectTestCaseApiImpl) ListBySprit(ctx context.Context, req *project_testcase_api.ListBySpritRequest) (*project_testcase_api.ListBySpritResponse, error) {
	emptyList := []*project_testcase_api.CaseInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.ListBySpritResponse{
			Code:     project_testcase_api.ListBySpritResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			CaseList: emptyList,
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.ListBySpritResponse{
			Code:     project_testcase_api.ListBySpritResponse_CODE_NO_PROJECT,
			ErrMsg:   "项目不存在",
			CaseList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.ListBySpritResponse{
			Code:     project_testcase_api.ListBySpritResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			CaseList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	linkItemList, err := testcase_dao.LinkSpritDao.ListBySprit(ctx, req.SpritId)
	if err != nil {
		return nil, err
	}

	caseIdList := []string{}
	linkItemMap := map[string]*testcase_dao.LinkSpritDbItem{}
	for _, linkItem := range linkItemList {
		caseIdList = append(caseIdList, linkItem.CaseId)
		linkItemMap[linkItem.CaseId] = linkItem
	}

	caseItemList, err := testcase_dao.CaseInfoDao.ListById(ctx, req.ProjectId, caseIdList)
	if err != nil {
		return nil, err
	}

	userIdList := []string{}
	for _, caseItem := range caseItemList {
		userIdList = append(userIdList, caseItem.CreateUserId)
		userIdList = append(userIdList, caseItem.UpdateUserId)
	}

	//获取关注信息
	watchItemMap, _, err := watch_dao.MyWatchDao.CalcWatchUserMap(ctx, req.ProjectId, uint32(project_watch_api.WATCH_TARGET_TYPE_WATCH_TARGET_TEST_CASE), caseIdList)
	if err != nil {
		return nil, err
	}
	//获取用户信息
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	//生成结果
	caseList := []*project_testcase_api.CaseInfo{}
	for _, caseItem := range caseItemList {
		caseInfo := caseItem.ToCaseInfo()
		createUser, ok := userItemMap[caseItem.CreateUserId]
		if ok {
			caseInfo.CreateDisplayName = createUser.BasicInfo.DisplayName
			caseInfo.CreateLogoUri = createUser.BasicInfo.LogoUri
		}
		updateUser, ok := userItemMap[caseItem.UpdateUserId]
		if ok {
			caseInfo.UpdateDisplayName = updateUser.BasicInfo.DisplayName
			caseInfo.UpdateLogoUri = updateUser.BasicInfo.LogoUri
		}
		caseInfo.UserPerm = apiImpl.calcCasePerm(sessionItem, projectItem, roleItem, caseItem)
		watchUserIdList, ok := watchItemMap[caseItem.CaseId]
		if ok {
			for _, watchUserId := range watchUserIdList {
				if watchUserId == sessionItem.UserId {
					caseInfo.MyWatch = true
				}
			}
		}
		linkItem, ok := linkItemMap[caseInfo.CaseId]
		if ok {
			caseInfo.ResultCount = linkItem.ResultCount
		} else {
			caseInfo.ResultCount = 0
		}
		caseList = append(caseList, caseInfo)
	}

	return &project_testcase_api.ListBySpritResponse{
		Code:     project_testcase_api.ListBySpritResponse_CODE_OK,
		CaseList: caseList,
	}, nil
}
